<?php
/**
 * +----------------------------------------------------------------------
 * | summer framework
 * +----------------------------------------------------------------------
 * | Copyright (c) 2020 https://github.com/suframe/think-admin All rights reserved.
 * +----------------------------------------------------------------------
 * | Author: summer <806115620@qq.com>  2020/3/26 10:40
 * +----------------------------------------------------------------------
 */
declare (strict_types=1);

namespace app\mall\logic\order;

use app\mall\enum\OpUserEnum;
use app\mall\enum\OrderRefundEnum;
use app\mall\enum\OrderStatusEnum;
use app\mall\enum\YesNoEnum;
use app\mall\Events;
use app\mall\exceptions\BaseException;
use app\mall\exceptions\GoodsException;
use app\mall\exceptions\OrderException;
use app\mall\exceptions\UserException;
use app\mall\logic\GoodsLogic;
use app\mall\model\MallGoodsStock;
use app\mall\model\MallLogisticsCompany;
use app\mall\model\MallOrder;
use app\mall\model\MallOrderEvaluate;
use app\mall\model\MallOrderLog;
use app\mall\model\MallOrderPay;
use app\mall\model\MallStore;
use app\mall\model\MallStoreClerk;
use app\mall\model\MallUser;
use app\mall\model\MallUserAddress;
use suframe\thinkAdmin\model\AdminUsers;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;

abstract class Base extends \app\mall\logic\Base
{

    /**
     * 取消订单
     * @param MallOrder $mallOrder
     * @param string $userType
     * @param int $uid
     * @param string $reason
     * @return bool
     * @throws BaseException
     */
    protected function doCancel(MallOrder $mallOrder, string $userType, int $uid, string $reason)
    {
        if (!$mallOrder->status_enum->canCancel()) {
            OrderException::throws(OrderException::$statusError);
        }
        //更改订单状态
        $mallOrder->status = OrderStatusEnum::CANCEL;
        $rs = $mallOrder->save();
        //增加日志
        $rs && $this->addLog(
            $mallOrder,
            $userType,
            $uid,
            $reason
        );
        //触发事件
        event(Events::ORDER_CANCEL, $mallOrder);
        return $rs;
    }

    /**
     * 完成订单
     * @param MallOrder $mallOrder
     * @param string $userType
     * @param int $uid
     * @param string $reason
     * @return bool
     * @throws BaseException
     */
    protected function doComplete(MallOrder $mallOrder, string $userType, int $uid, string $reason)
    {
        if (!$mallOrder->status_enum->canCompleted()) {
            OrderException::throws(OrderException::$statusError);
        }
        //更改订单状态
        $mallOrder->status = OrderStatusEnum::COMPLETED;
        $rs = $mallOrder->save();
        //增加日志
        $rs && $this->addLog(
            $mallOrder,
            $userType,
            $uid,
            $reason
        );
        //触发事件
        event(Events::ORDER_COMPLETE, $mallOrder);
        return $rs;
    }

    /**
     * 订单评价
     * @param MallOrder $mallOrder
     * @param string $userType
     * @param int $uid
     * @param int $rate
     * @param string $content
     * @param array $images
     * @return bool
     * @throws BaseException
     */
    protected function doEvaluate(MallOrder $mallOrder, string $userType, int $uid, int $rate, string $content, array $images = [])
    {
        if (!$mallOrder->canEvaluate($userType)) {
            OrderException::throws(OrderException::$statusError);
        }
        //更改订单状态
        $model = MallOrderEvaluate::create([
            'sn' => $mallOrder->sn,
            'store_id' => $mallOrder->store_id,
            'goods_id' => $mallOrder->goods_id,
            'goods_stock_id' => $mallOrder->goods_stock_id,
            'user_type' => $userType,
            'uid' => $uid,
            'rate' => $rate,
            'content' => $content,
            'images' => $images,
        ]);
        $rs = $model->save();
        if (!$rs) {
            OrderException::throws(OrderException::$evaluateFail);
        }

        //增加日志
        $rs && $this->addLog(
            $mallOrder,
            $userType,
            $uid,
            '评价订单' . ($content ? ':' . $content : '')
        );
        //触发事件
        event(Events::ORDER_EVALUATE, $mallOrder);
        return $rs;
    }

    /**
     * 发货
     * @param MallOrder $mallOrder
     * @param int $logisticsCompanyId 快递公司id
     * @param string $logistics_sn 发货单号
     * @param string $userType
     * @param int $userId
     * @param string $desc
     * @return bool
     * @throws BaseException
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    protected function doSend(
        MallOrder $mallOrder,
        int $logisticsCompanyId,
        string $logistics_sn,
        string $userType,
        int $userId,
        string $desc = ''
    ): bool
    {
        if ($mallOrder->status_enum->canSend()) {
            OrderException::throws(OrderException::$statusError);
        }

        $logisticsCompany = MallLogisticsCompany::where('enable', YesNoEnum::YES)->find($logisticsCompanyId);
        if (!$logisticsCompany) {
            OrderException::throws(OrderException::$logisticsCompanyNotFound);
        }

        $mallOrder->status = OrderStatusEnum::SHIPPED;
        $mallOrder->logistics_company_id = $logisticsCompanyId;
        $mallOrder->logistics_sn = $logistics_sn;
        $mallOrder->logistics_time = date('Y-m-d H:i:s');
        $rs = $mallOrder->save();
        if (!$rs) {
            OrderException::throws(OrderException::$sendFail);
        }
        //增加日志
        $this->addLog($mallOrder, $userType, $userId, $desc);
        //触发事件
        event(Events::ORDER_SEND, $mallOrder);
        return $rs;
    }

    /**
     * 退款
     * @param bool $audit
     * @param MallOrder $mallOrder
     * @param string $userType
     * @param int $userId
     * @param string $desc
     * @return bool
     * @throws BaseException
     */
    protected function doRefund(bool $audit, MallOrder $mallOrder, string $userType, int $userId, string $desc): bool
    {
        if (!$mallOrder->status_enum->canRefund()) {
            OrderException::throws(OrderException::$statusError);
        }
        Db::startTrans();
        try {
            if ($audit) {
                //审核通过
                $mallOrder->apply_refund = OrderRefundEnum::COMPLETED;
                $rs = $mallOrder->save();
                if ($rs) {
                    //更新订单状态
                    $mallOrder->status = OrderStatusEnum::REFUND;
                    $mallOrder->save();
                }
                $desc = "退款申请通过" . ($desc ? ':' . $desc : '');
            } else {
                //审核不通过
                $mallOrder->apply_refund = OrderRefundEnum::REFUSE;
                $rs = $mallOrder->save();
                $desc = "退款申请被拒绝" . ($desc ? ':' . $desc : '');
            }
            if (!$rs) {
                OrderException::throws(OrderException::$refundFail);
            }
            Db::commit();
            //增加日志
            $this->addLog($mallOrder, $userType, $userId, $desc);
            //触发事件
            event($audit ? Events::ORDER_REFUND_SUCCESS : Events::ORDER_REFUND_FAIL, $mallOrder);
            return $rs;
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    protected function createSn(): string
    {
        return date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    }

    public function addLog(MallOrder $mallOrder, string $userType, int $userId, string $content, array $images = [])
    {
        $log = MallOrderLog::create([
            'sn' => $mallOrder->sn,
            'user_type' => $userType,
            'uid' => $userId,
            'content' => $content,
        ]);
        return $log->save();
    }

}